#include "Load.h"
using namespace std; 

map<int, int> getRes;
int curResIndex = 0;
bool MySearchCallback(int id, void* arg) 
{
  getRes[curResIndex] = id;
  curResIndex = curResIndex + 1;
  return true; // keep going
}

Load::Load()
{

}
Load::~Load()
{

}
void Load::__001_fixStringNum(char* num, int fixDigit)
{
	int index = 0, fixTime = 0;
	char temp = 'c';
	int isOver = 0;
	//find index of num
	while(num[index] != '.')
	{
		index = index + 1;
	}
	//fix the number to 6 presion double
	while(fixTime < fixDigit)
	{
		if(isOver == 0)
		{
		    temp = num[index];
			num[index] = num[index + 1];
			num[index + 1] = temp;
		}
		else if(isOver == 1)
		{
			isOver = 2;
			num[index] = '0';
		}
		else
		{
			num[index] = '0';
			num[index + 1] = '\0';
		}
		index = index + 1;
		if(isOver == 0 && num[index + 1] == '\0')
		{
			isOver = 1;
		}
		fixTime = fixTime + 1;
	}
}
map<int, char*> Load::__002_myStrtok(char *stringList, char *delimiter)
{
	map<int, char*> list_str;
	char *getTok = NULL;
	int index = 0;
	getTok = strtok(stringList, delimiter);
	while(getTok != NULL)
	{
		list_str[index] = getTok;
		getTok = strtok(NULL, delimiter);
		index = index + 1;
	}
	return list_str;
}
void Load::__003_insertToRtree(Edge storeEdge,  int inIndex)
{
	double temp = 0.0;
	double min_x = storeEdge.from->in_lat;
	double min_y = storeEdge.from->in_long;
	double max_x = storeEdge.to->in_lat;
	double max_y = storeEdge.to->in_long;
	if(min_x > max_x)
	{
		temp = min_x;
		min_x = max_x;
		max_x = temp;
	}
	if(min_y > max_y)
	{
		temp = min_y;
		min_y = max_y;
		max_y = temp;
	}
	Rect newRect = Rect(min_x, min_y, max_x, max_y);
	(*this).tree.Insert(newRect.min, newRect.max, inIndex);
}
double Load::__004_countPointToLineDistant(Node node, Node edge_node1, Node edge_node2)
{
	double x0 = node.in_lat * 10000, y0 = node.in_long* 10000;
	double x1 = edge_node1.in_lat* 10000, y1 = edge_node1.in_long* 10000;
	double x2 = edge_node2.in_lat* 10000, y2 = edge_node2.in_long* 10000;
	return (fabs((y2 - y1) * x0 +(x1 - x2) * y0 + ((x2 * y1) -(x1 * y2)))) / (sqrt(pow(y2 - y1, 2) + pow(x1 - x2, 2)));
}
void Load::ACT001_loadWA_Node(char* filePath)
{
	int read_id = 0;
	char read_lat[READ_STR_NUM_MAX], read_long[READ_STR_NUM_MAX];
	char *newStr = NULL;
	FILE *fp = fopen(filePath, "r");
	Node node_store;
	while(fscanf(fp, " %d%s%s", &read_id, read_lat, read_long) == 3)
	{
		(*this).__001_fixStringNum(read_lat, NUM_POSITION_FIX);
		(*this).__001_fixStringNum(read_long, NUM_POSITION_FIX);
		node_store = Node(atof(read_lat), atof(read_long));
		(*this).list_node[read_id] = node_store;
	}
	fclose(fp);
}
void Load::ACT002_loadWA_Edge(char *filePath_edge, char *filePath_edgeGeometry)
{
	//variable of processing edge file
	FILE *fp_edge = fopen(filePath_edge, "r");
	int id_edge = 0, id_nodeFrom = 0, id_nodeTo = 0;
	int cost = 0;
	//variable of processing edge geometry
	FILE *fp_edgeG = fopen(filePath_edgeGeometry, "r");
	char read_one_line[READ_STR_BYTE_IN_ONE_LINE + 2];
	map<int, char*> list_getStr;
	int size_list_getStr = 0;
	Edge edge;
	Node *get_from, *get_to;
	int get_cost = 0;
	double get_length;
	char *temp = NULL;
	//start to read two file at a time
	int i = 0;
	while(fscanf(fp_edge, " %d%d%d%d", &id_edge, &id_nodeFrom, &id_nodeTo, &cost) == 4)
	{
		//read one line of file-edgeGeometry at a time 
		fgets(read_one_line, READ_STR_BYTE_IN_ONE_LINE, fp_edgeG);
		//split the line string according to the "^" symbol
		list_getStr = (*this).__002_myStrtok(read_one_line, STR_EDGE_G_DELIMITER);
		//store edge information to map
		size_list_getStr = list_getStr.size();
		get_from = &((*this).list_node[id_nodeFrom]);
		get_to = &((*this).list_node[id_nodeTo]);
		get_cost = cost;
		if(size_list_getStr % 2 == 0)  //it has road name information
		{
			temp = list_getStr[3];
		}
		else  //it has no road name information
		{
			temp = list_getStr[2];
		}
		(*this).__001_fixStringNum(temp, NUM_LENGTH_FIX);
		get_length = atof(temp);
		(*this).list_edge[i] = Edge(get_from, get_to, get_length, get_cost);
		//store information to R-tree
		(*this).__003_insertToRtree((*this).list_edge[i], i);
		i++;
	}
	fclose(fp_edge);
	fclose(fp_edgeG);
	//search test
	//(*this).ACT003_getSearchResult(Node(476.6969, -1221.3639));
}
Ans Load::ACT003_getSearchResult(Node node)
{
	Ans getAns;
	int getRoadId = -1;
	double count = 0.0, getMin = -1.0, myRange = RANGE, getConfd = 0.0;
	//initial variable
	curResIndex = 0;
	getRes.clear();
	double min_x, min_y, max_x, max_y, temp;
	//do rectangle when no point is covered
	while(getRes.size() <= 0)
	{
		min_x = node.in_lat - myRange;
		min_y = node.in_long - myRange;
		max_x = node.in_lat + myRange;
		max_y = node.in_long + myRange;
		Rect rect = Rect(min_x, min_y, max_x, max_y);
		(*this).tree.Search(rect.min, rect.max, MySearchCallback, NULL);
		myRange = myRange * 10;
	}
	//find the right point
	for(int i = 0; i < curResIndex; i++)
	{
		count = (*this).__004_countPointToLineDistant(node, *((*this).list_edge[getRes[i]].from), *((*this).list_edge[getRes[i]].to));
		if(getMin == -1)
		{
			getMin = count;
		}
		else
		{
			if(count <= getMin)
			{
				getMin = count;
				getRoadId = getRes[i];
				if(count < getMin)
				{
					getConfd = 1.0;
				}
				else
				{
				    getConfd = getConfd + 1.0;
				}
			}
		}
	}
	getAns.pointID = getRoadId;
	getAns.confidence = (double)1.0 / getConfd;
	return getAns;
}
map<int, Node> Load::GET001_list_node()
{
	return (*this).list_node;
}